#ifndef _X_STRING_H_
#define _X_STRING_H_
#ifdef max
#undef max
#endif

#ifdef min
#undef min
#endif

#include <hash_map>

#ifdef CORE_EXPORTS
#define CORE_API __declspec(dllexport)
#else
#define CORE_API __declspec(dllimport)
#endif	//CORE_EXPORTS

namespace XGC
{
	#define HeaderFromMember( TYPE, MEMBER_POINT, MEMBER_NAME ) ((TYPE *)( MEMBER_POINT - (((TYPE *)0)->MEMBER_NAME) ))

	class xStaticStringPool;
	class CORE_API xString
	{
	private:
		xgc_size	len;
		xgc_size	allocated_len;
		xgc_lpstr	str;

	public:
		xString()
			: str( xgc_nullptr )
			, len( 0 )
			, allocated_len( 0 )
		{
		}

		xString( const xString &rhs )
			: str( xgc_nullptr )
			, len( 0 )
			, allocated_len( 0 )
		{
			assign( rhs );
		}

		xString( xgc_lpcstr rval )
			: str( xgc_nullptr )
			, len( 0 )
			, allocated_len( 0 )
		{
			assign( rval );
		}

		~xString()
		{
			clear();
		}

		xString& operator=( const xString& rhs )
		{
			return assign( rhs );
		}

		xString& operator=( xgc_lpcstr rhs )
		{
			return assign( rhs );
		}

		xgc_lpcstr c_str()const
		{
			return str;
		}

		xgc_size length()const
		{
			return len;
		}

		xgc_size capacity()const
		{
			return allocated_len;
		}

		xString& assign ( xgc_lpcstr rval );

		//-----------------------------------//
		//
		// [10/19/2012 Albert.xu]
		// assign xString object 
		//-----------------------------------//
		xString& assign ( const xString& rval );

		//-----------------------------------//
		//
		// [10/19/2012 Albert.xu]
		// clear string 
		//-----------------------------------//
		xgc_void clear();

		//-----------------------------------//
		//
		// [10/19/2012 Albert.xu]
		// truncate space 
		//-----------------------------------//
		xString& truncate( xgc_size length )
		{
			len = std::min(length, len);
			str[len] = 0;

			return *this;
		}

		xString& set_size( xgc_size length )
		{
			if (length >= allocated_len)
				expand( length - len );

			len = length;
			str[len] = 0;

			return *this;
		}

		xString& insert( xgc_size pos, xgc_lpcstr val,	xgc_size length = -1 );

		xString& insert ( xgc_size pos, xgc_char c );

		xString& insert ( xgc_size pos, xgc_wchar wc);

		XGC_INLINE xgc_bool is_unichar( xgc_wchar c )
		{
			return (c != (xgc_wchar) -2) && (c != (xgc_wchar) -1);
		}

		XGC_INLINE xString& append ( xgc_lpcstr val )
		{  
			ASSERT_RETURN(val != NULL, *this);

			return insert (-1, val, -1);
		}

		XGC_INLINE xString& append ( xgc_lpcstr val, xgc_size length )
		{  
			ASSERT_RETURN( length == 0 || val != NULL, *this);

			return insert (-1, val, length );
		}

		XGC_INLINE xString& append ( xgc_lpcstr val, xgc_char c )
		{  
			return insert (-1, c );
		}

		XGC_INLINE xString& append ( xgc_lpcstr val, xgc_wchar c )
		{  
			return insert (-1, c );
		}

		XGC_INLINE xString& prepend ( xgc_lpcstr val )
		{  
			ASSERT_RETURN(val != NULL, *this);

			return insert (0, val, -1);
		}

		XGC_INLINE xString& prepend ( xgc_lpcstr val, xgc_size length )
		{  
			ASSERT_RETURN( length == 0 || val != NULL, *this);

			return insert (0, val, length );
		}

		XGC_INLINE xString& prepend ( xgc_lpcstr val, xgc_char c )
		{  
			return insert (0, c );
		}

		XGC_INLINE xString& prepend ( xgc_lpcstr val, xgc_wchar c )
		{  
			return insert (0, c );
		}

		xString& overwrite( xgc_size pos, xgc_lpcstr val, xgc_size length = -1 );

		xString& erase ( xgc_size pos, xgc_size length );

		xgc_bool operator < (const xString& rhs )const{ return strcmp(str,rhs.str) < 0; }
		xgc_bool operator == (const xString& rhs )const{ return strcmp(str,rhs.str) == 0; }
	private:
		void expand ( xgc_size length );
	};
	
	class CORE_API xStaticString
	{
	friend xStaticStringPool;
	private:
		xStaticStringPool *pool;
		xgc_lpcstr str;

		explicit xStaticString( xStaticStringPool *_pool, xgc_lpstr _str );

	public:
		explicit xStaticString();
		xStaticString( const xStaticString& rval );

		XGC_INLINE xStaticString& operator=( const xStaticString& rval );
		XGC_INLINE xgc_bool operator< ( const xStaticString& rval )const;
		XGC_INLINE xgc_bool operator< ( const xgc_astring& rval )const;
		XGC_INLINE xgc_bool operator< ( xgc_lpcstr rval )const;

		XGC_INLINE xgc_bool operator==( const xStaticString& rval )const;
		XGC_INLINE xgc_bool operator==( xgc_lpcstr rval )const;

		XGC_INLINE xgc_lpcstr c_str()const;

		XGC_INLINE xgc_size length()const;

		xgc_void assign( const xStaticString& rval );
		xgc_void clear();
	};

	class CORE_API xStaticStringPool
	{
	friend class xStaticString;
	private:
		struct Header
		{
			xgc_uint16 size;
			xgc_uint16 remainder;
		};

		struct String
		{
			xgc_int16	len;
			xgc_int16	ref;
			xgc_int16	next;
			xgc_int16	prev;
			xgc_char	drop;
			xgc_char	str[1];

			xgc_int16 AddRef(){ return ++ref; }
			xgc_int16 Release()
			{
				xgc_int16 tmp = --ref;
				//if( tmp <= 0 )
				//{
				//	String* pString = HeaderFromMember( String, str, str );
				//	pString->drop = true;

				//	String* pNextString = HeaderFromMember( String, str+next, str );
				//	String* pPrevString = HeaderFromMember( String, str+prev, str );
				//	if( pPrevString < this )
				//	{
				//		pPrevString->next += next;
				//	}

				//	if( pNextString > this )
				//	{
				//		pNextString->prev += prev;
				//	}
				//}

				return tmp;
			}
		};

		typedef stdext::hash_compare< xgc_lpcstr, xgc_bool (*)( xgc_lpcstr, xgc_lpcstr ) > key_compare;
		typedef std::list< xgc_lpstr >	storage_list_t;
		typedef stdext::hash_map< xgc_lpcstr, xgc_lpstr, key_compare > hash_table_t;

		hash_table_t	*const_table;
		storage_list_t	*storage_list;
		xgc_size	storage_next, storage_prev;
		xgc_size	this_size;
		xgc_size	default_size;

		xgc_long32	ref_count;

		xStaticStringPool(); // not allow
		xStaticStringPool( const xStaticStringPool& rhs ); // not allow

	private:
		//-----------------------------------//
		//
		// [10/19/2012 Albert.xu]
		// insert string to chunk 
		//-----------------------------------//
		xgc_lpstr Insert( xgc_lpcstr str, xgc_int32 len, xgc_size *hash = xgc_nullptr );

		//-----------------------------------//
		//
		// [10/19/2012 Albert.xu]
		// reference count increase
		//-----------------------------------//
		xgc_long32 AddRef(){ return ++ref_count; }

		//-----------------------------------//
		//
		// [10/19/2012 Albert.xu]
		// reference count decrease 
		//-----------------------------------//
		xgc_long32 Release(){ xgc_long32 tmp = --ref_count; if( tmp <= 0 ) delete this; return tmp; }

	public:
		//-----------------------------------//
		//
		// [10/19/2012 Albert.xu]
		// constructor 
		//-----------------------------------//
		explicit xStaticStringPool( xgc_size size );

		//-----------------------------------//
		//
		// [10/19/2012 Albert.xu]
		// destructor 
		//-----------------------------------//
		~xStaticStringPool();

		//-----------------------------------//
		//
		// [10/19/2012 Albert.xu]
		// clear all storage 
		//-----------------------------------//
		xgc_void Clear();

		//-----------------------------------//
		//
		// [10/19/2012 Albert.xu]
		// insert string to chunk manager 
		//-----------------------------------//
		xgc_lpstr Insert( xgc_lpcstr str );

		//-----------------------------------//
		//
		// [10/19/2012 Albert.xu]
		// insert string assign xString 
		//-----------------------------------//
		xStaticString DupString( xgc_lpcstr rval );
	};

	XGC_INLINE xgc_size hash_value( const xStaticString _Str )
	{	// hash NTBS to size_t value
		xgc_lpcstr p;
		xgc_uint32 h = 5381;

		for (p = _Str.c_str(); *p != '\0'; p++)
			h = (h << 5) + h + *p;

		return h;
	}

	XGC_INLINE xgc_lpcstr xStaticString::c_str() const
	{
		return str;
	}

	XGC_INLINE xgc_size xStaticString::length() const
	{
		return str?HeaderFromMember( xStaticStringPool::String, str, str )->len:-1;
	}

	XGC_INLINE xStaticString& xStaticString::operator=( const xStaticString& rval )
	{
		assign( rval );
		return *this;
	}

	XGC_INLINE xgc_bool xStaticString::operator< ( const xStaticString& rval )const
	{
		return strcmp( str, rval.str ) < 0;
	}

	XGC_INLINE xgc_bool xStaticString::operator< ( const xgc_astring& rval )const
	{
		return strcmp( str, rval.c_str() ) < 0;
	}

	XGC_INLINE xgc_bool xStaticString::operator< ( xgc_lpcstr rval )const
	{
		return strcmp( str, rval ) < 0;
	}

	XGC_INLINE xgc_bool xStaticString::operator==( const xStaticString& rval )const
	{
		return str == rval.str;
	}

	XGC_INLINE xgc_bool xStaticString::operator==( xgc_lpcstr rval )const
	{
		if( !str || !rval )
			return false;

		return strcmp( str, rval ) == 0;
	}
};
#endif // _X_STRING_H_